package com.sinodata.bsm.center.expression;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;

/**
 * 
 * <p>
 * Description: 
 * </p>
 *
 * @author hehaiyang_itsm
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-7-10 上午11:42:55          hehaiyang_itsm        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class BatchCalctor {

    public static final String VAR_PREFIX = "$";

    protected Map<String, Object> varsMap = new HashMap<String, Object>();

    private static Logger logger = Logger.getLogger(BatchCalctor.class);

    private ChartCalctor chartCalctor = new ChartCalctor(this);

    private final static Pattern pattern = Pattern.compile("^-?\\d+(?:.\\d+)?(?:(?:[Ee]-?\\d+)|[lLdDfF])?$");

    private DecimalFormat numFormat = new DecimalFormat("#.##");

    /**
     * 
    <MetaData bgImg="" bgColor="16750848" bgAlpha="0.4697986577181208">
    <c name="resid">14800</c>
    <element type="psd.widgets.primer.RollFan" x="139" y="107" w="202" h="136" id="layer0_1">
    <c name="CPU平均用户使用率">110100000000001</c>
    <p name="color" type="color">eventColor($resid,$CPU平均用户使用率)</p>
    <p name="text" type="string">CPU平均用户使用率</p>
    <p name="fontSize" type="uint">12</p>
    <p name="value" type="string">prop($resid,$CPU平均用户使用率)</p>
    <p name="dataUnit" type="string">%</p>
    </element>
    </MetaData>
     * @param xml
     */
    public String calcXml(String inXml) {
        try {
            Document doc = DocumentHelper.parseText(inXml);
            Element root = doc.getRootElement();
            for (Iterator<Element> iterator = root.elementIterator("c"); iterator.hasNext();) {
                Element ce = iterator.next();
                String constName = ce.attribute("name").getText();
                Object constVal = getElementValue(ce);
                varsMap.put(VAR_PREFIX + constName, constVal);
            }

            for (Iterator<Element> iterator = root.elementIterator("element"); iterator.hasNext();) {
                Element element = iterator.next();
                try {
                    calcElement(element);
                } catch (Exception e) {
                    logger.error(e.getMessage() + ":" + element.asXML());
                }
            }
            return doc.asXML();
        } catch (DocumentException e) {
            logger.error("输入的数据格式出错" + e.getMessage());
        }
        return null;
    }

    public void calcElement(Element element) throws Exception {
        //第一步处理常量<c/>
        for (Iterator<Element> iterator = element.elementIterator("c"); iterator.hasNext();) {
            Element ce = iterator.next();
            String cName = ce.attribute("name").getText().trim();
            Object cVal = getElementValue(ce);
            varsMap.put(VAR_PREFIX + cName, cVal);
        }
        //第二步处理变量<v/>
        for (Iterator<Element> iterator = element.elementIterator("v"); iterator.hasNext();) {
            Element ve = iterator.next();
            String vName = ve.attribute("name").getText();
            Object vVal = Expressions.eval(ve.getTextTrim(), varsMap);
            varsMap.put(VAR_PREFIX + vName, vVal);
        }
        //第三步计算<p/>
        for (Iterator<Element> iterator = element.elementIterator("p"); iterator.hasNext();) {
            Element pe = iterator.next();
            if (pe.attribute("calc") != null && pe.attributeValue("calc").equals("false")) {
                continue;
            }
            try {
                String exp = pe.getTextTrim();
                if (exp.contains(VAR_PREFIX)) {
                    Object pVal = Expressions.eval(pe.getTextTrim(), varsMap);
                    if (pVal != null) {
                        //------------参考PropertyValuePersistentThread  匹配数值型字符串，并格式化-----------
                        String pValStr = pVal.toString();
                        if ("NaN".equals(pValStr) || "N/A".equals(pValStr) || "".equals(pValStr)) {
                            pValStr = "";
                        } else if (pattern.matcher(pValStr).find()) {
                            pValStr = numFormat.format(Double.parseDouble(pValStr));

                        }
                        //------------------------------
                        pe.setText(pValStr);
                        pe.addAttribute("exp", exp);
                    } else {
                        pe.setText("");
                    }
                }
            } catch (Exception e) {
                pe.setText("");
                logger.error(e.getMessage());
            }
        }
        //第四部如果是chart类型单独计算
        Element chartElement = element.element("cdata");
        if (chartElement != null) {
            chartCalctor.calcChart(element);
        }
        //第五步处理reapter类型
        if (element.attributeValue("type").endsWith("Reapter")) {
            reaptElement(element);
        }
        //最后递归执行子element
        for (Iterator<Element> iterator = element.elementIterator("element"); iterator.hasNext();) {
            calcElement(iterator.next());
        }
    }

    /**
     * 计算循环元素 
     * @param element
     * @throws Exception 
     */
    private void reaptElement(Element element) throws Exception {
        Element node = (Element) element.selectSingleNode("p[@name='value']");
        Object obj = Expressions.eval(node.attributeValue("exp"), varsMap);
        Object[] reaptObjs = null;
        if (obj instanceof List) {
            reaptObjs = ((List) obj).toArray();
        } else if (obj instanceof Object[]) {
            reaptObjs = (Object[]) obj;
        } else {
            throw new Exception("reapt element's value must is instance of List or array:\n[" + element.asXML() + "]");
        }
        varsMap.put("$reapter", reaptObjs);
        List<Element> childElems = element.elements("element");
        for (Element c : childElems) {
            c.detach();
        }
        for (int i = 0; i < reaptObjs.length; i++) {
            Element group = element.addElement("element");
            group.addAttribute("type", "group");
            group.addAttribute("id", element.attributeValue("id") + "_group" + i);
            for (int j = 0; j < childElems.size(); j++) {
                Element copyChild = childElems.get(j).createCopy();
                copyChild.addAttribute("id", group.attributeValue("id") + "_" + j);
                for (Iterator<Element> iterator = copyChild.elementIterator(); iterator.hasNext();) {
                    Element p = iterator.next();
                    String exp = p.getTextTrim();
                    exp = exp.replaceAll("\\$reapter", "\\$reapter[" + i + "]");
                    p.setText(exp);
                }
                group.add(copyChild);
            }
        }
    }

    /**
     * 预处理计算的表达式
     * @param inXml
     */
    public static void pretreatment(String inXml) {
        Document doc;
        try {
            doc = DocumentHelper.parseText(inXml);
            Element root = doc.getRootElement();
            preElement(root);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 
     * @param element
     */
    private static void preElement(Element element) {
        String resType = element.attributeValue("resType");
        for (Iterator<Element> iterator = element.elementIterator("p"); iterator.hasNext();) {
            Element pe = iterator.next();
            pe.addAttribute("resType", resType);
            try {
                pe.getTextTrim();
            } catch (Exception e) {
            }
        }
        //递归预处理子element
        for (Iterator<Element> iterator = element.elementIterator("element"); iterator.hasNext();) {
            preElement(iterator.next());
        }
    }

    public static Object getElementValue(Element element) {
        String valStr = element.getTextTrim();
        String type = element.attributeValue("type");
        if (type != null) {
            if (type.equals("uint") || type.equalsIgnoreCase("BSM.RES") || type.equalsIgnoreCase("PROPERTY") || type.equalsIgnoreCase("RESTYPE") || type.equalsIgnoreCase("ATTRIBUTE")) {
                return Long.parseLong(valStr);
            }
        }
        return valStr;
    }

    public static void main(String[] args) throws Exception {
        //        String expr = "maxChild(1L,2L)";
        //        expr ="childProp($reapter.getId(),$磁盘使用率)";
        //        expr = expr.replaceAll("\\$reapter", "\\$reapter[i]");
        //        System.out.println(expr);
        Map varsMap1 = new HashMap();
        varsMap1.put("$arr", new String[] { "a", "b", "c" });
        Object result = Expressions.eval("$arr[0]", varsMap1);
        System.out.println(result);
    }
}
